package com.suyeer.fastwechat.util;

import com.suyeer.basic.util.LogUtil;
import com.suyeer.fastwechat.bean.base.WeChatProperties;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;

import java.net.*;
import java.util.HashSet;

import static com.suyeer.fastwechat.util.FwConstUtil.WX_PARAM_ACCESS_TOKEN;
import static com.suyeer.fastwechat.util.FwConstUtil.WX_PARAM_TICKET;

/**
 * @author jun 2018/11/29.
 */
public class FwUdpUtil {

    private final static HashSet<String> UDP_CLIENT_IP_LIST = WeChatProperties.getInstance().getUdpClientIpList();
    private final static HashSet<String> UDP_SERVER_IP_LIST = WeChatProperties.getInstance().getUdpServerIpList();

    private final static int PORT = WeChatProperties.getInstance().getUdpPort();
    private final static int PORT_LENGTH = 3;
    private final static int DATA_LENGTH = 512;
    private final static int TIME_OUT = 100;
    private final static String DEFAULT_DATA = "0";

    public static String udpClient(String body) {
        try {
            if (UDP_SERVER_IP_LIST.size() == 0) {
                throw new Exception("未配置 UDP 服务器ip: udpServerIp");
            }
            DatagramSocket socket = new DatagramSocket(0);
            for (int i = 0; i < PORT_LENGTH; i++) {
                int port = PORT + i;
                for (String ip : UDP_SERVER_IP_LIST) {
                    try {
                        socket.setSoTimeout(TIME_OUT);
                        byte[] bytes = body.getBytes(Consts.UTF_8);
                        InetAddress host = InetAddress.getByName(ip);
                        DatagramPacket request = new DatagramPacket(bytes, bytes.length, host, port);
                        DatagramPacket response = new DatagramPacket(new byte[DATA_LENGTH], DATA_LENGTH);
                        socket.send(request);
                        socket.receive(response);
                        return new String(response.getData(), 0, response.getLength(), Consts.UTF_8);
                    } catch (SocketTimeoutException e) {
                        LogUtil.error("服务器 {}:{} 链接超时, 将尝试链接下一个端口或ip...", ip, port);
                    } catch (Exception e) {
                        LogUtil.error(e);
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.error("{} UDP客户端请求服务端失败, {}", FwConstUtil.ERROR, e.getMessage());
        }
        return null;
    }

    public static void startUdpServer() {
        try {
            DatagramSocket socket = null;
            for (int i = 0; i < PORT_LENGTH; i++) {
                int port = PORT + i;
                try {
                    socket = new DatagramSocket(port);
                    break;
                } catch (BindException e) {
                    LogUtil.error("端口 [{}] 已被占用, 将尝试端口 [{}] ...", port, (port + 1));
                } catch (Exception e) {
                    LogUtil.error(e);
                }
            }
            while (socket != null) {
                try {
                    DatagramPacket request = new DatagramPacket(new byte[DATA_LENGTH], DATA_LENGTH);
                    socket.receive(request);
                    String result = getDataString(request);
                    byte[] data = result.getBytes(Consts.UTF_8);
                    DatagramPacket response = new DatagramPacket(data, data.length, request.getAddress(), request.getPort());
                    socket.send(response);
                } catch (Exception e) {
                    LogUtil.error(e);
                }
            }
        } catch (Exception e) {
            LogUtil.error(e);
        }
    }

    private static String getDataString(DatagramPacket request) {
        String address = request.getAddress().getHostAddress();
        String requestStr = new String(request.getData(), 0, request.getLength(), Consts.UTF_8);
        if (UDP_CLIENT_IP_LIST.size() > 0 && !UDP_CLIENT_IP_LIST.contains(address)) {
            return DEFAULT_DATA;
        }
        if (WX_PARAM_ACCESS_TOKEN.equalsIgnoreCase(requestStr)) {
            return getData(FwUtil.getAccessToken());
        }
        if (WX_PARAM_TICKET.equalsIgnoreCase(requestStr)) {
            return getData(FwUtil.getJsApiTicket());
        }
        return DEFAULT_DATA;
    }

    private static String getData(String str) {
        if (StringUtils.isNotBlank(str)) {
            return str;
        }
        return DEFAULT_DATA;
    }

}
